package com.study.demoservice.service.impl;

import com.atguigu.annotation.WebLog;
import com.study.demoservice.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

import java.time.LocalTime;

@Service
@Slf4j
public class PayServiceImpl implements PayService {

    private final int totalNum = 100000;

    /**
     * @Retryable 标记当前方法会使用重试机制
     *      value: 同 include, 抛哪些异常会触发 重试机制
     *      exclude: 哪些异常不触发 重试机制
     *      maxAttempts: 最大重试次数, 默认 3 次(包括第一次调用)
     *      backoff: 重试等待策略, 默认使用 @Backoff 注解
     * @Backoff 重试回退策略（立即重试还是等待一会儿再重试）
     *      value: 同 delay, 重试的间隔时间, 默认 1000L
     *      maxDelay: 重试次数之间的最大时间间隔, 默认为 0, 如果小于 delay 的设置, 则默认为 3000L
     *      multiplier: 等比时间间隔, delay 的时间间隔, 默认为 0, 表示固定暂停 1 秒后进行重试, 如果设置为1.5, 则第一次重试为 2s, 第二次为 3s, 第三次为 4.5s
     *      delayExpression: 等差时间间隔, 固定时间间隔
     *
     * @param num
     * @return
     */
    @Retryable(value = {Exception.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000, delayExpression = "5000"))
    @Override
    public int minGoodsNum(int num) {
        log.info("减库存开始->{}", LocalTime.now());
        log.info("库存=>{}", totalNum);
        if (num < 0) {
            throw new IllegalArgumentException("数量不对");
        }
        log.info("减库存执行结果->{}", LocalTime.now());
        return totalNum - num;
    }

    /**
     * 使用@Recover注解，当重试次数达到设置的次数的时候，还是失败抛出异常，执行的回调函数。
     * 第一入参是 @Retryable 中抛出的异常或者其父类, 其他参数要与 @Retryable 保持一致, 返回值也要一致
     */
    @Recover
    @Override
    public int recover(Exception e, int num) {
        log.warn("减库存失败！！！{}, 入参为:{}", LocalTime.now(), num);
        return totalNum;
    }
}
